#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <winsock2.h>
#include "GeneralFunctions.h"
#include "Types.h"
#include "SocketSendRecvTools.h"
 
TMode ConvertModeNameToTMode(char *mode)
{
if (0 == strcmp(mode , "Clock"))
	return MODE_CLOCK;
else if (0 == strcmp(mode , "Battery"))
	return MODE_BATTERY;
else if (0 == strcmp(mode , "Interceptor"))
	return MODE_INTERCEPTOR;
else if (0 == strcmp(mode , "IronDomeManager"))
	return MODE_MANAGER;
else if (0 == strcmp(mode , "RealWorldSimulator"))
	return MODE_SIMULATOR;
else 
	return (TMode)-1;
}


void PrintActionType(TActionType ActionType)
{
	TActionType Action = ActionType;
	switch (ActionType)
	{
		case ACTION_BEGINNING_OF_ROUND:
			printf("ACTION_BEGINNING_OF_ROUND\n");
			break;
		case ACTION_END_OF_ROUND:
			printf("ACTION_END_OF_ROUND\n");
			break;
		case ACTION_END_OF_ROUND_TO_CLOCK:
			printf("ACTION_END_OF_ROUND_TO_CLOCK\n");
			break;
		case ACTION_LAUNCH_INTERCEPTOR:
			printf("ACTION_LAUNCH_INTERCEPTOR\n");
			break;	
		case ACTION_LAUNCH_REFUSAL:
			printf("ACTION_LAUNCH_REFUSAL\n");
			break;	
		case ACTION_UPDATE_INTERCEPTOR_ON_ROCKET_INFO:
			printf("ACTION_UPDATE_INTERCEPTOR_ON_ROCKET_INFO\n");
			break;	
		case ACTION_SELF_DESTRUCT:
			printf("ACTION_SELF_DESTRUCT\n");
			break;	
		case ACTION_CHANGE_BATTERIES:
			printf("ACTION_CHANGE_BATTERIES\n");
			break;	
		case ACTION_UPDATE_CURRENT_POSITION:
			printf("ACTION_UPDATE_CURRENT_POSITION\n");
			break;
		case ACTION_UPDATE_CURRENT_DIRECTION:
			printf("ACTION_UPDATE_CURRENT_DIRECTION\n");
			break;
		case ACTION_UPDATE_POSITIONS_MAP:
			printf("ACTION_UPDATE_POSITIONS_MAP\n");
			break;
		case ACTION_NOTIFY_INTERCEPTOR_TO_CHANGE_BATTERY:
			printf("ACTION_NOTIFY_INTERCEPTOR_TO_CHANGE_BATTERY\n");
			break;
		case ACTION_INITIAL_INTERCEPTOR_INFO_UPDATE:
			printf("ACTION_INITIAL_INTERCEPTOR_INFO_UPDATE\n");
			break;
		case ACTION_REGISTRATION:
			printf("ACTION_REGISTRATION\n");
			break;
		case ACTION_ROCKET_EXPLODED:
			printf("ACTION_ROCKET_EXPLODED\n");
			break;
		case ACTION_INTERCEPTED:
			printf("ACTION_INTERCEPTED\n");
			break;
		case ACTION_IN_BATTERY:
			printf("ACTION_IN_BATTERY\n");
			break;
		case ACTION_END_OF_GAME:
			printf("ACTION_END_OF_GAME\n");
			break;
	}
}



void FinishedStartUpSequence()
{
	printf("FINISHED START UP SEQUENCE\n");
	//getchar();
}



void PrintRoundStarted(int RoundNumber)
{
		printf("==========================================\n");
		printf("ROUND %d STARTED\n", RoundNumber);
}


void PrintRoundEnded()
{
		printf("ROUND ENDED\n\n");
}


HANDLE CreateThreadSimple(  LPTHREAD_START_ROUTINE StartAddress, 
                            LPVOID ParameterPtr, 
                            LPDWORD ThreadIdPtr )
{
    return CreateThread(
                        NULL,            /*  default security attributes */
                        0,                /*  use default stack size */
                        StartAddress,    /*  thread function */
                        ParameterPtr,    /*  argument to thread function */
                        0,                /*  use default creation flags */
                        ThreadIdPtr );    /*  returns the thread identifier */
}

/* CreateProcessSimple
 * -------------------
 * CreateProcessSimple uses the win32 API to create a process that runs the
 * command in 'CommandLine'. it uses the win32 API function CreateProcess()
 * using default values for most parameters.
 *
 * Accepts: 
 * --------
 * CommandLine - a windows generic string containing the command that the new 
 *               process performs. ( See CreateProcess( documentation for more ).
 * ProcessInfoPtr - an output parameter, used to return a PROCESS_INFORMATION
 *					structure containing data about the process that was created.
 *					( See CreateProcess() documentation for more ).
  * Returns:
 * --------
 * the output of CreateProcess().
 */
BOOL CreateProcessSimple( LPTSTR CommandLine, PROCESS_INFORMATION *ProcessInfoPtr )
{
    STARTUPINFO    startinfo = { sizeof( STARTUPINFO ), NULL, 0 }; /* <ISP> here we */
    /* initialize a "Neutral" STARTUPINFO variable. Supplying this to */
    /* CreateProcess() means we have no special interest in this parameter. */
    /* This is equivalent to what we are doing by supplying NULL to most other */
    /* parameters of CreateProcess(). */ 

    return CreateProcess( NULL, /*  No module name (use Command line). */
        CommandLine,            /*  Command line. */
        NULL,                    /*  Process handle not inheritable. */
        NULL,                    /*  Thread handle not inheritable. */
        FALSE,                    /*  Set handle inheritance to FALSE. */
        NORMAL_PRIORITY_CLASS,    /*  creation/priority flags. */
        NULL,                    /*  Use parent's environment block. */
        NULL,                    /*  Use parent's starting directory. */
        &startinfo,                /*  Pointer to STARTUPINFO structure. */
        ProcessInfoPtr            /*  Pointer to PROCESS_INFORMATION structure. */
    );
}

void VerifyNumOfArgs (TMode Mode, int argc)
{
	int Flag=0;
	int CorrectNumberOfArgs = 999;
	switch (Mode)
	{
	case MODE_INTERCEPTOR:
		if ( argc != 13)
		{
			CorrectNumberOfArgs = 13;
			Flag = 1;
		}
		break;
	case MODE_BATTERY:
		if ( argc != 10)
		{
			CorrectNumberOfArgs = 10;
			Flag = 1;
		}
			break;
	case MODE_MANAGER:
		if (( argc != 12)&&(argc != 11))
		{
			CorrectNumberOfArgs = 12;
			Flag = 1;
		}
			break;
	case MODE_SIMULATOR:
		if (( argc != 21)&&(argc != 20))
		{
			CorrectNumberOfArgs = 21;
			Flag = 1;
		}
		break;
	case MODE_CLOCK:
		if ( argc != 5)
		{
			CorrectNumberOfArgs = 5;
			Flag = 1;
		}
		break;
	}
	if (Flag == 1)
	{
		printf("The correct number of argument is %d\nThe number of argument we recieved is %d\n  ",CorrectNumberOfArgs,argc);
	//	getchar();
		exit(1);
		
	}
}

void PrintErrorAndExit(TError Error)
{
	// print the appropriate error to the end file in case of error
		switch (Error)	
	{
		case ERROR_ALLOCATING_MEMORY:
			printf("Error allocating memory\n");
			break;
		case ERROR_CREATING_THREAD:
			printf("Error creating thread\n");
			break;
		case ERROR_AT_WSAStartup:
			printf("Error at WSAStartup\n");
			break;
		case ERROR_WAITING_FOR_SINGLE_OBJECT:
			printf("Error waiting for single object\n");
			break;
		case ERROR_SENDING_MESSAGE:
			printf("Error sending message\n");
			break;
		case ERROR_WAITING_FOR_MULTIPLE_OBJECT:
			printf("Error waiting for multiple object\n");
			break;
		case ERROR_RECEIVING_MESSAGE:
			printf("Error receiving message\n");
			break;
		case ERROR_WRITING_TO_FILE:
			printf("Error writing to file\n");
			break;
		default:
			printf("General error\n");
	}
//	getchar();
}

int WaitForClockToNotifyBeginningOfRound(SOCKET ClockSocket)
{
	TActionType Action;
	int RoundNumber;
	ReceiveActionType(&Action, ClockSocket);
	if (Action == ACTION_BEGINNING_OF_ROUND)
	{
		ReceiveInteger(&RoundNumber, ClockSocket);
		PrintRoundStarted(RoundNumber);
		return RoundNumber;
	}
	PrintErrorAndExit(GENERAL_ERROR);
	return -1;
}

BOOL NotifyClockEndOfRound(SOCKET ClockSocket)
{
	if (SendActionType(ACTION_END_OF_ROUND_TO_CLOCK, ClockSocket) == TRNS_SUCCEEDED)
	{
		PrintRoundEnded();
		return TRUE;		
	}
	return FALSE;
}

void IdentifyToServer(TMode NodeType, SOCKET ServerSocket)
{
	SendInteger(NodeType, ServerSocket);
}

void PrintEndOfGame()
{
	printf("\n~~~~ END OF GAME ~~~~\n");
//	getchar();
}








